﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Windows.Media;

namespace System.Windows.Art
{
    public abstract class ColorSpaceBase
    {
        internal static readonly List<ColorSpaceBase> pool = new List<ColorSpaceBase>();
        private static readonly Object singletonLock = new Object();
        
        private readonly ColorChannelCollection channels;
        private readonly String friendlyName;

        internal ColorSpaceBase(params ColorChannelTemplate[] channelTemplates)
        {
            lock (ColorSpaceBase.singletonLock)
            {
                if (ColorSpaceBase.pool.Contains(this)) throw new NotSupportedException();
                else
                {
                    ColorSpaceBase.pool.Add(this);
                    this.friendlyName = this.GetType().Name.ToLowerInvariant();

                    if (channelTemplates == null) channelTemplates = new ColorChannelTemplate[0];
                    var count = channelTemplates.Length;
                    var channelArray = new ColorChannel[count];
                    var nameList = new List<String>(count);
                    for (Int32 i = 0; i < count; i++)
                    {
                        var template = channelTemplates[i];
                        var name = template.Name;
                        if (String.IsNullOrEmpty(name)) throw new ArgumentOutOfRangeException("channelTemplates");
                        if (nameList.Contains(name)) throw new ArgumentOutOfRangeException("channelTemplates");

                        nameList.Add(name);
                        channelArray[i] = new ColorChannel(this, template);
                    }
                    this.channels = new ColorChannelCollection(channelArray);
                    this.OnChannelsAquired();
                }
            }
        }

        protected virtual void OnChannelsAquired() { }

        public ColorChannelCollection Channels { get { return this.channels; } }

        public abstract Type OwnerType { get; }
        public abstract IColor FromColorBase(Color value);

        public sealed override Boolean Equals(Object obj)
        {
            if (obj == null) return false;
            else return obj.GetType() == this.GetType();
        }

        public sealed override Int32 GetHashCode()
        {
            return this.GetType().GetHashCode();
        }

        public override String ToString()
        {
            return this.friendlyName;
        }
    }

    public abstract class ColorSpace<T> : ColorSpaceBase where T : IColor
    {
        public ColorSpace(params ColorChannelTemplate[] channelTemplates)
            : base(channelTemplates)
        {
        }

        public sealed override Type OwnerType { get { return typeof(T); } }

        public abstract T FromColor(Color value);
        public sealed override IColor FromColorBase(Color value) { return this.FromColor(value); }
    }
}
